package repositories

import (
	"Godzilla/common/convert"
	"Godzilla/common/db"
	"Godzilla/common/encryption"
	"Godzilla/common/mysql"
	"Godzilla/common/responses"
	"Godzilla/models"
	"errors"
	"math"
	"strconv"
	"time"
)


type UserManager struct {
	table	string
	db		*db.DB
}

func NewUserManager() (UserManager, error){
	db, err := db.NewDB("mysql", db.Dsn())
	if err != nil {
		return UserManager{}, err
	}
	return UserManager{
		table: "user",
		db:    db,
	}, err
}

func (manager *UserManager)SelectUserById(userId string)  (user *models.User, err error) {
	var (
		sql 	string
	)

	sql = "SELECT * FROM "+ manager.table +" WHERE id = ? LIMIT 1"
	row, errRows := manager.db.Query(sql, userId)
	if errRows != nil {
		return &models.User{}, errRows
	}
	defer row.Close()

	result := mysql.GetResultRow(row)
	if len(result) == 0 {
		return &models.User{}, errors.New("用户不存在")
	}
	user = &models.User{}
	convert.DataToStructByTagSql(result, user)
	return user, nil
}

func (manager *UserManager)InsertUser(username string, password string) (int64, error)  {
	var (
		hashPassword string
		sql			 string
	)

	hashPassword = encryption.EncryptMd5(password)

	user := &models.User{
		ID:           0,
		NickName:     username,
		UserName:     username,
		Email:        "",
		Mobile:       "",
		HashPassword: hashPassword,
		AuthToken:    "",
		CreateAt:     time.Now().Format("2006-01-02 15:04:05"),
		UpdateAt:     time.Now().Format("2006-01-02 15:04:05"),
		ExpireAt:     time.Now().Format("2006-01-02 15:04:05"),
		Status:       1,
	}
	sql = "INSERT INTO " + manager.table + "(nickname, username, email, mobile, password, auth_token, create_at, update_at, expire_at,status) VALUES(?,?,?,?,?,?,?,?,?,?)"
	result, errSql := manager.db.PrepareAndExec(sql,user.NickName, user.UserName, user.Email, user.Mobile, user.HashPassword, user.AuthToken, user.CreateAt, user.UpdateAt, user.ExpireAt, user.Status)
	if errSql != nil {
		return 0, errSql
	}

	returnId, err := result.LastInsertId()
	return  returnId, err
}

func (manager *UserManager)UpdateUserById(userId int64, username string) error {
	var (
		sql 	string
	)


	sql = "UPDATE " + manager.table + " SET username = ? WHERE id = " + strconv.FormatInt(userId, 10)
	_, err := manager.db.PrepareAndExec(sql, username)
	if err != nil {
		return err
	}
	return nil
}

func (manager *UserManager)DeleteUserById(userId int64) (bool, error) {
	var (
		sql 	string
	)


	sql = "DELETE FROM " + manager.table + " WHERE id = ?"
	_, err := manager.db.PrepareAndExec(sql, userId)
	if err != nil {
		return false, err
	}
	return true, nil
}

func (manager *UserManager)SelectUsers(where string, page int64, size int64, sort string, filed string) (results responses.Results, err error) {
	var (
		sql 		string
		count		int64
		totalPage   int64
		sizeStr     string
		offset      int64
		offsetStr   string
	)

	count, err = manager.CountUsers(where)
	if err != nil{
		return
	}
	if count == 0 {
		results.Total = count
		results.Size = size
		results.Page = page
		results.Lists = make([]interface{}, 0)
		return results, nil
	}


	totalPage = int64(math.Ceil(float64(count) / float64(size)))
	sizeStr = strconv.FormatInt(size, 10)
	offset = (page -1 ) * size
	offsetStr = strconv.FormatInt(offset, 10)


	sql = "SELECT * FROM " + manager.table + " WHERE " + where  + " ORDER BY " + filed + "  " + sort +" LIMIT "+ offsetStr + " , " + sizeStr
	rows, err := manager.db.Query(sql)
	defer rows.Close()
	if err != nil {
		return results, err
	}

	data := mysql.GetResultRows(rows)
	if len(data) == 0 {
		results.Total = count
		results.Page = page
		results.Size = size
		results.TotalPage = totalPage
		results.Lists = make([]interface{}, 0)
		return results, err
	}

	var userArray []*models.User
	for i := 0; i < len(data); i++ {
		user := &models.User{}
		convert.DataToStructByTagSql(data[i], user)
		userArray = append(userArray, user)
	}

	results.Total = count
	results.Page = page
	results.Size = size
	results.TotalPage = totalPage
	results.Lists = userArray
	return
}

func (manager *UserManager)CountUsers(where string) (count int64, err error) {
	var (
		sql	string
	)

	sql = "SELECT COUNT(*) FROM " + manager.table + " WHERE " + where
	rows, err := manager.db.Query(sql)
	defer rows.Close()
	if err != nil {
		return 0, err
	}
	if rows.Next() {
		rows.Scan(&count)
	}
	return count, err
}

func (manager *UserManager)CheckToken(token string) (int64, bool) {
	var (
		sql 	string
	)
	sql = "SELECT * FROM " + manager.table + " WHERE auth_token = ? LIMIT 1"
	row, err := manager.db.Query(sql, token)
	if err != nil {
		return 0, false
	}
	defer row.Close()

	result := mysql.GetResultRow(row)
	if len(result) == 0 {
		return 0, false
	}
	user := &models.User{}
	convert.DataToStructByTagSql(result, user)
	return user.ID, true

}
